#include <stdio.h>
#include <stdlib.h>
#include "uthash.h" //开源hashtable http://troydhanson.github.io/uthash/

//CONSTANT_Utf8_info结构的常量池表
struct utf8_constant_pool_table
{
    int id; /* 索引 */
    char *value;
    UT_hash_handle hh;
};

struct utf8_constant_pool_table *utf8s = NULL;

void add_utf8(struct utf8_constant_pool_table *s)
{
    HASH_ADD_INT(utf8s, id, s);
}

struct utf8_constant_pool_table *find_utf8(int utf8_id)
{
    struct utf8_constant_pool_table *s;

    HASH_FIND_INT(utf8s, &utf8_id, s);
    return s;
}

//解析常量池
void resolve_constant_pool(FILE *fp);

//解析访问标志
void resolve_access_flags(FILE *fp);

//解析类索引、父类索引与接口索引集合
void resolve_class_index(FILE *fp);

//解析字段表
void resolve_field_table(FILE *fp);

//解析方法表
void resolve_method_table(FILE *fp);

//解析属性表
void resolve_attr_table(FILE *fp);

//浮点数大小端转换
float floatb2l(float value);
//双精度浮点数大小端转换
double doubleb2l(double value);
//整数 大端转小端
int intb2l(int);
//短整型 大端转小端
short shortb2l(short);
//长整型 大端转小端
long longb2l(long);

int main(int argc, char *argv [])
{
    FILE *fp = fopen(argv[1], "r");
    if (fp == NULL)
    {
        printf("%s not find\n", argv[1]);
        exit(1);
    }
    //魔数
    unsigned int magic;
    fread(&magic, sizeof(magic), 1, fp);
    magic = intb2l(magic);
    printf("魔数：%#x\n", magic);
    //次版本号
    unsigned short minor_version;
    fread(&minor_version, sizeof(minor_version), 1, fp);
    minor_version = shortb2l(minor_version);
    printf("次版本号：%#x\n", minor_version);
    //主版本号
    unsigned short major_version;
    fread(&major_version, sizeof(major_version), 1, fp);
    major_version = shortb2l(major_version);
    printf("主版本号：%#x\n", major_version);
    //常量池
    resolve_constant_pool(fp);

    //访问标志 access_flags u2
    resolve_access_flags(fp);

    //解析类索引、父类索引与接口索引集合
    resolve_class_index(fp);

    //字段个数
    unsigned short fields_count;
    fread(&fields_count, sizeof(fields_count), 1, fp);
    fields_count = shortb2l(fields_count);
    printf("字段个数：%d\n", fields_count);

    //解析字段表
    for (int i = 0; i < fields_count; i++)
    {
        resolve_field_table(fp);
    }

    //方法个数
    unsigned short methods_count;
    fread(&methods_count, sizeof(methods_count), 1, fp);
    methods_count = shortb2l(methods_count);
    printf("方法个数：%d\n", methods_count);

    //解析方法表
    for (int i = 0; i < methods_count; i++)
    {
        resolve_method_table(fp);
    }

    //附加属性个数
    unsigned short attributes_count;
    fread(&attributes_count, sizeof(attributes_count), 1, fp);
    attributes_count = shortb2l(attributes_count);
    printf("附加属性个数：%d\n", attributes_count);

    //解析属性表
    resolve_attr_table(fp);

    fclose(fp);
    return 0;
}

short shortb2l(short b)
{
    return b << 8 | b >> 8;
}

int intb2l(int b)
{
    return (b << 24 & 0xff000000) | (b << 8 & 0x00ff0000) | (b >> 24 & 0x000000ff) | (b >> 8 & 0x0000ff00);
}

long longb2l(long b)
{
    return (b << 56 & 0xff00000000000000) | (b << 40 & 0x00ff000000000000) |
           (b << 24 & 0x0000ff0000000000) | (b << 8 & 0x000000ff00000000) | (b >> 56 & 0x00000000000000ff) | (b >> 40 & 0x000000000000ff00) | (b >> 24 & 0x0000000000ff0000) | (b >> 8 & 0x00000000ff000000);
}

typedef union FLOAT_CONV {
    float f;
    char c[4];
} float_conv;

float floatb2l(float value)
{
    float_conv d1, d2;
    d1.f = value;
    d2.c[0] = d1.c[3];
    d2.c[1] = d1.c[2];
    d2.c[2] = d1.c[1];
    d2.c[3] = d1.c[0];
    return d2.f;
}

typedef union DOUBLE_CONV {
    double d;
    char c[8];
} double_conv;

double doubleb2l(double value)
{
    double_conv d1, d2;
    d1.d = value;
    d2.c[0] = d1.c[7];
    d2.c[1] = d1.c[6];
    d2.c[2] = d1.c[5];
    d2.c[3] = d1.c[4];
    d2.c[4] = d1.c[3];
    d2.c[5] = d1.c[2];
    d2.c[6] = d1.c[1];
    d2.c[7] = d1.c[0];
    return d2.d;
}

//解析常量池
void resolve_constant_pool(FILE *fp)
{
    unsigned short constant_pool_count;
    fread(&constant_pool_count, sizeof(constant_pool_count), 1, fp);
    constant_pool_count = shortb2l(constant_pool_count) - 1;
    printf("常量池容量计数：%zd\n", constant_pool_count);
    printf("Constant pool:\n");
    for (int i = 0; i < constant_pool_count; i++)
    {
        //获取标签
        unsigned char tag;
        fread(&tag, sizeof(tag), 1, fp);
        switch (tag)
        {

            unsigned short class_index;
            unsigned short name_and_type_index;
            unsigned short name_index;
            unsigned short descriptor_index;
            unsigned short string_index;
            int bytes;
            long longbytes;
            float fbytes;
            double dbytes;
            char *typename;             //常量类型名
            unsigned short byte_length; //utf8 byte个数
            char *utf8content;
        case 9:
            typename = "Fieldref";
            fread(&class_index, sizeof(class_index), 1, fp);
            fread(&name_and_type_index, sizeof(name_and_type_index), 1, fp);
            class_index = shortb2l(class_index);
            name_and_type_index = shortb2l(name_and_type_index);
            printf("#%d = %s \t\t #%zd.#%zd\n", i + 1, typename, class_index, name_and_type_index);
            break;
        case 10:
            typename = "Methodref";
            fread(&class_index, sizeof(class_index), 1, fp);
            fread(&name_and_type_index, sizeof(name_and_type_index), 1, fp);
            class_index = shortb2l(class_index);
            name_and_type_index = shortb2l(name_and_type_index);
            printf("#%d = %s \t\t #%zd.#%zd\n", i + 1, typename, class_index, name_and_type_index);
            break;

        case 11:
            typename = "InterfaceMethodref";
            fread(&class_index, sizeof(class_index), 1, fp);
            fread(&name_and_type_index, sizeof(name_and_type_index), 1, fp);
            class_index = shortb2l(class_index);
            name_and_type_index = shortb2l(name_and_type_index);
            printf("#%d = %s \t\t #%zd.#%zd\n", i + 1, typename, class_index, name_and_type_index);
            break;
        case 7:
            typename = "Class";
            fread(&name_index, sizeof(name_index), 1, fp);
            name_index = shortb2l(name_index);
            printf("#%d = %s \t\t #%zd\n", i + 1, typename, name_index);
            break;
        case 1:
            typename = "Utf8";
            fread(&byte_length, sizeof(byte_length), 1, fp);
            byte_length = shortb2l(byte_length);
            //申请字符串内存 多一个字节存放\0表示字符串的结尾
            utf8content = (char *)malloc((byte_length + 1) * sizeof(char));
            fread(utf8content, byte_length * sizeof(char), 1, fp);
            utf8content[byte_length] = '\0';
            printf("#%d = %s \t\t %s\n", i + 1, typename, utf8content);
            //添加到utf8常量表里
            struct utf8_constant_pool_table *utf8 = malloc(sizeof(struct utf8_constant_pool_table));
            utf8->id = i + 1;
            utf8->value = utf8content;
            add_utf8(utf8);
            break;
        case 12:
            typename = "NameAndType";
            fread(&name_index, sizeof(name_index), 1, fp);
            name_index = shortb2l(name_index);
            fread(&descriptor_index, sizeof(descriptor_index), 1, fp);
            descriptor_index = shortb2l(descriptor_index);
            printf("#%d = %s \t #%zd.#%zd\n", i + 1, typename, name_index, descriptor_index);
            break;
        case 8:
            typename = "String";
            fread(&string_index, sizeof(string_index), 1, fp);
            string_index = shortb2l(string_index);
            printf("#%d = %s \t\t #%zd\n", i + 1, typename, string_index);
            break;
        case 3:
            typename = "Integer";
            fread(&bytes, sizeof(bytes), 1, fp);
            bytes = intb2l(bytes);
            printf("#%d = %s \t\t %d\n", i + 1, typename, bytes);
            break;
        case 4:
            typename = "Float";
            fread(&fbytes, sizeof(fbytes), 1, fp);
            fbytes = floatb2l(fbytes);
            printf("#%d = %s \t\t %f\n", i + 1, typename, fbytes);
            break;
        case 5:
            typename = "Long";
            fread(&longbytes, sizeof(longbytes), 1, fp);
            longbytes = longb2l(longbytes);
            printf("#%d = %s \t\t %ld\n", i + 1, typename, longbytes);
            i++; //Long类型占用2个索引位置
            break;
        case 6:
            typename = "Double";
            fread(&dbytes, sizeof(double), 1, fp);
            dbytes = doubleb2l(dbytes);
            printf("#%d = %s \t\t %f\n", i + 1, typename, dbytes);
            i++; //Double类型占用2个索引位置
            break;
        default:
            break;
        }
    }
}

//解析访问标志
void resolve_access_flags(FILE *fp)
{
    //访问标志
    unsigned short access_flags;
    fread(&access_flags, sizeof(access_flags), 1, fp);
    access_flags = shortb2l(access_flags);
    printf("访问标志：%#x\n", access_flags);
    printf("flags：");
    //解析一下访问标志
    //ACC_PUBLIC    0x0001      是否为Public类型
    if ((access_flags & 0x0001) == 0x0001)
    {
        printf("%s", "ACC_PUBLIC ");
    }
    //ACC_FINAL     0x0010      是否被声明为final，只有类可以设置
    if ((access_flags & 0x0010) == 0x0010)
    {
        printf("%s", "ACC_FINAL ");
    }
    //ACC_SUPER     0x0020      是否允许使用invokespecial字节码指令的新语义
    if ((access_flags & 0x0020) == 0x0020)
    {
        printf("%s", "ACC_SUPER ");
    }
    //ACC_INTERFACE     0x0200     标志这是一个接口
    if ((access_flags & 0x0200) == 0x0200)
    {
        printf("%s", "ACC_INTERFACE ");
    }
    //ACC_ABSTRACT     0x0200     标志这是一个接口
    if ((access_flags & 0x0400) == 0x0400)
    {
        printf("%s", "ACC_ABSTRACT ");
    }

    //ACC_SYNTHETIC     0x1000     标志这是一个接口
    if ((access_flags & 0x1000) == 0x1000)
    {
        printf("%s", "ACC_SYNTHETIC ");
    }

    //ACC_ANNOTATION     0x1000     标志这是一个接口
    if ((access_flags & 0x2000) == 0x2000)
    {
        printf("%s", "ACC_ANNOTATION ");
    }

    //ACC_ENUM     0x4000     标志这是一个接口
    if ((access_flags & 0x4000) == 0x4000)
    {
        printf("%s", "ACC_ENUM ");
    }
    printf("\n");
}

//解析类索引、父类索引与接口索引集合
void resolve_class_index(FILE *fp)
{
    //类索引 u2
    unsigned short class_index;
    fread(&class_index, sizeof(class_index), 1, fp);
    class_index = shortb2l(class_index);
    printf("类索引：#%d\n", class_index);

    //父类索引 u2
    unsigned short parent_class_index;
    fread(&parent_class_index, sizeof(parent_class_index), 1, fp);
    parent_class_index = shortb2l(parent_class_index);
    printf("父类索引：#%d\n", parent_class_index);

    //接口索引集合
    unsigned short interfaces_count;
    fread(&interfaces_count, sizeof(interfaces_count), 1, fp);
    interfaces_count = shortb2l(interfaces_count);
    printf("接口索引个数：%d\n", interfaces_count);
    printf("接口索引集合：");
    unsigned short interface_index;
    if (interfaces_count)
    {
        for (int i = 0; i < interfaces_count; i++)
        {

            fread(&interface_index, sizeof(interface_index), 1, fp);
            interface_index = shortb2l(interface_index);
            printf("#%d ", interface_index);
        }
    }
    printf("\n");
}

//解析字段表
//field_info {
//    u2 access_flags;
//    u2 name_index;
//    u2 descriptor_index;
//    u2 attributes_count;
//    attibute_info attibutes[attributes_count];
//}
void resolve_field_table(FILE *fp)
{
    //access_flags u2
    //访问标志
    // | 标志名 | 值 | 说明 |
    // | --- | --- | --- |
    // | ACC_PUBLIC | 0x0001 | 声明为public，可以从包外访问 |
    // | ACC_PRIVATE | 0x0002 | 声明为private，只能在定义该字段的类中访问 |
    // | ACC_PROTECTED | 0x0004 | 声明为protected，子类可以访问 |
    // | ACC_STATIC | 0x0008 | 声明为static |
    // | ACC_FINAL | 0x0010 | 声明为final，对象构造好之后，就不能直接设置该字段了 |
    // | ACC_VOLATILE | 0x0040 | 声明为volatile，被标识的字段无法缓存 |
    // | ACC_TRANSIENT | 0x0080 | 声明为transient，被标识的字段不会为持久化对象管理器所写入或读取 |
    // | ACC_SYNTHETIC | 0x1000 | 被标识的字段由编译器产生，而没有写源代码中 |
    // | ACC_ENUM | 0x4000 | 该字段声明为某个枚举类型（enum）的成员 |
    unsigned short access_flags;
    fread(&access_flags, sizeof(access_flags), 1, fp);
    access_flags = shortb2l(access_flags);
    printf("字段表访问标志：%#x\n", access_flags);
    printf("field flags：");
    //解析一下访问标志
    //ACC_PUBLIC    0x0001      是否为Public类型
    if ((access_flags & 0x0001) == 0x0001)
    {
        printf("%s", "ACC_PUBLIC ");
    }

    //ACC_PRIVATE    0x0002      声明为private，只能在定义该字段的类中访问
    if ((access_flags & 0x0002) == 0x0002)
    {
        printf("%s", "ACC_PRIVATE ");
    }

    //ACC_PROTECTED    0x0004      声明为protected，子类可以访问
    if ((access_flags & 0x0004) == 0x0004)
    {
        printf("%s", "ACC_PROTECTED ");
    }

    //ACC_STATIC    0x0008      声明为static
    if ((access_flags & 0x0008) == 0x0008)
    {
        printf("%s", "ACC_STATIC ");
    }

    //ACC_FINAL    0x0010      声明为final，对象构造好之后，就不能直接设置该字段了
    if ((access_flags & 0x0010) == 0x0010)
    {
        printf("%s", "ACC_FINAL ");
    }

    //ACC_VOLATILE    0x0040      声明为volatile，被标识的字段无法缓存
    if ((access_flags & 0x0040) == 0x0040)
    {
        printf("%s", "ACC_VOLATILE ");
    }

    //ACC_TRANSIENT    0x0080      声明为transient，被标识的字段不会为持久化对象管理器所写入或读取
    if ((access_flags & 0x0080) == 0x0080)
    {
        printf("%s", "ACC_TRANSIENT ");
    }

    //ACC_SYNTHETIC    0x1000      被标识的字段由编译器产生，而没有写源代码中
    if ((access_flags & 0x1000) == 0x1000)
    {
        printf("%s", "ACC_SYNTHETIC ");
    }

    //ACC_ENUM    0x4000      该字段声明为某个枚举类型（enum）的成员
    if ((access_flags & 0x4000) == 0x4000)
    {
        printf("%s", "ACC_ENUM ");
    }

    printf("\n");

    //u2 name_index;
    unsigned short name_index;
    fread(&name_index, sizeof(name_index), 1, fp);
    name_index = shortb2l(name_index);
    printf("字段名：#%d\n", name_index);
    //u2 descriptor_index;
    unsigned short descriptor_index;
    fread(&descriptor_index, sizeof(descriptor_index), 1, fp);
    descriptor_index = shortb2l(descriptor_index);
    printf("字段描述符：#%d\n", descriptor_index);
    //    u2 attributes_count;
    //    attibute_info attibutes[attributes_count];
    unsigned short attributes_count;
    fread(&attributes_count, sizeof(attributes_count), 1, fp);
    attributes_count = shortb2l(attributes_count);
    printf("字段属性个数：%d\n", attributes_count);
    for (int i = 0; i < attributes_count; i++)
    {
        //解析字段属性表
        resolve_attr_table(fp);
    }
}

//解析方法表
void resolve_method_table(FILE *fp)
{
    //access_flags 方法访问标志
    unsigned short access_flags;
    fread(&access_flags, sizeof(access_flags), 1, fp);
    access_flags = shortb2l(access_flags);
    printf("方法表访问标志：%#x\n", access_flags);
    printf("method flags：");
    //ACC_PUBLIC    0x0001      是否为Public类型
    if ((access_flags & 0x0001) == 0x0001)
    {
        printf("%s", "ACC_PUBLIC ");
    }

    //ACC_PRIVATE    0x0002      声明为private，只能在定义该字段的类中访问
    if ((access_flags & 0x0002) == 0x0002)
    {
        printf("%s", "ACC_PRIVATE ");
    }

    //ACC_PROTECTED    0x0004      声明为protected，子类可以访问
    if ((access_flags & 0x0004) == 0x0004)
    {
        printf("%s", "ACC_PROTECTED ");
    }

    //ACC_STATIC    0x0008      声明为static
    if ((access_flags & 0x0008) == 0x0008)
    {
        printf("%s", "ACC_STATIC ");
    }

    //ACC_FINAL    0x0010      声明为final，对象构造好之后，就不能直接设置该字段了
    if ((access_flags & 0x0010) == 0x0010)
    {
        printf("%s", "ACC_FINAL ");
    }

    //ACC_SYNCHRONIZED    0x0020      声明为synchronized，对该方法的调用，将包装在同步锁（monitor）里
    if ((access_flags & 0x0020) == 0x0020)
    {
        printf("%s", "ACC_SYNCHRONIZED ");
    }

    //ACC_BRIDGE    0x0040      声明为bridge方法，由编译器产生
    if ((access_flags & 0x0040) == 0x0040)
    {
        printf("%s", "ACC_BRIDGE ");
    }

    //ACC_VARARGES  0x0080  表示方法带有变长参数
    if ((access_flags & 0x0080) == 0x0080)
    {
        printf("%s", "ACC_VARARGES ");
    }

    //ACC_NATIVE    0x0100      声明为native，该方法不是用Java语言实现的
    if ((access_flags & 0x0100) == 0x0100)
    {
        printf("%s", "ACC_NATIVE ");
    }

    //ACC_ABSTRACT      0x0400    声明为abstract，该方法没有实现代码
    if ((access_flags & 0x0400) == 0x0400)
    {
        printf("%s", "ACC_ABSTRACT ");
    }

    //ACC_STRICT    0x0800      声明为strictfp，使用FP-strict浮点模式
    if ((access_flags & 0x0800) == 0x0800)
    {
        printf("%s", "ACC_STRICT ");
    }

    //ACC_SYNTHETIC    0x1000      该方法是由编译器合成的，而不是由源代码编译出来的
    if ((access_flags & 0x1000) == 0x1000)
    {
        printf("%s", "ACC_SYNTHETIC ");
    }

    printf("\n");

    //name_index
    unsigned short name_index;
    fread(&name_index, sizeof(name_index), 1, fp);
    name_index = shortb2l(name_index);
    printf("方法名索引：#%d\n", name_index);
    printf("方法名：%s\n", find_utf8(name_index)->value);
    //u2 descriptor_index;
    unsigned short descriptor_index;
    fread(&descriptor_index, sizeof(descriptor_index), 1, fp);
    descriptor_index = shortb2l(descriptor_index);
    printf("方法描述符：#%d\n", descriptor_index);
    //u2 attributes_count;
    unsigned short attributes_count;
    fread(&attributes_count, sizeof(attributes_count), 1, fp);
    attributes_count = shortb2l(attributes_count);
    printf("方法属性个数：%d\n", attributes_count);
    for (int i = 0; i < attributes_count; i++)
    {
        //解析属性表
        resolve_attr_table(fp);
    }
}

//解析属性表
void resolve_attr_table(FILE *fp)
{
    //1.ConstantValue 常量
    // ```
    // ConstantValue_attribute {
    //     u2 attribute_name_index;
    //     u4 attribute_length;
    //     u2 constantvalue_index;
    // }
    // ```
    //属性名索引
    unsigned short attribute_name_index;

    fread(&attribute_name_index, sizeof(attribute_name_index), 1, fp);
    attribute_name_index = shortb2l(attribute_name_index);
    printf("属性名索引：#%d\n", attribute_name_index);
    struct utf8_constant_pool_table *attribute_name_table = find_utf8(attribute_name_index);
    char *value = attribute_name_table->value;

    printf("属性名：%s\n", value);

    //属性字节长度
    unsigned int attribute_length;
    fread(&attribute_length, sizeof(attribute_length), 1, fp);
    attribute_length = intb2l(attribute_length);
    printf("属性字节长度：%d\n", attribute_length);

    //ConstantValue
    if (!strcmp(value, "ConstantValue"))
    {
        //常量索引
        unsigned short constantvalue_index;
        fread(&constantvalue_index, sizeof(constantvalue_index), 1, fp);
        constantvalue_index = shortb2l(constantvalue_index);
        printf("常量索引：#%d\n", constantvalue_index);
    }
    else if (!strcmp(value, "Synthetic")) //Synthetic
    {
        //do nothing
    }
    else if (!strcmp(value, "SourceFile"))
    {
        unsigned short sourcefile_index;
        fread(&sourcefile_index, sizeof(sourcefile_index), 1, fp);
        sourcefile_index = shortb2l(sourcefile_index);
        printf("附加属性名索引：#%d, ", sourcefile_index);

        printf("附加属性名：%s\n", find_utf8(sourcefile_index)->value);
    }
    else if (!strcmp(value, "LineNumberTable"))
    {
        //代码行属性（用于调试）
        unsigned short line_number_table_length;
        fread(&line_number_table_length, sizeof(line_number_table_length), 1, fp);
        line_number_table_length = shortb2l(line_number_table_length);
        printf("line_number_table_length:%d\n", line_number_table_length);
        for (int i = 0; i < line_number_table_length; i++)
        {
            unsigned short start_pc;
            fread(&start_pc, sizeof(start_pc), 1, fp);
            start_pc = shortb2l(start_pc);
            printf("start_pc:%d 对应", start_pc);

            unsigned short line_number;
            fread(&line_number, sizeof(start_pc), 1, fp);
            line_number = shortb2l(line_number);
            printf("line_number:%d\n", line_number);
        }
    }
    else if (!strcmp(value, "LocalVariableTable"))
    {
        //局部变量表（用于调试，注意：需要用javac -g 编译才有该属性信息）
        //LocalVariableTable_attribte {
        //     u2 attribute_name_index;
        //     u4 attribute_length;
        //     u2 local_variable_table_length;
        //     {
        //         u2 start_pc;
        //         u2 length;
        //         u2 name_index;
        //         u2 descriptor_index;
        //         u2 index;
        //     } local_variable_table[local_variable_table_length]
        // }
        unsigned short local_variable_table_length;
        fread(&local_variable_table_length, sizeof(local_variable_table_length), 1, fp);
        local_variable_table_length = shortb2l(local_variable_table_length);
        printf("local_variable_table_length:%d\n", local_variable_table_length);
        for (int i = 0; i < local_variable_table_length; i++)
        {
            unsigned short start_pc;
            fread(&start_pc, sizeof(start_pc), 1, fp);
            start_pc = shortb2l(start_pc);
            printf("start_pc:%d ,", start_pc);

            unsigned short length;
            fread(&length, sizeof(length), 1, fp);
            length = shortb2l(length);
            printf("length:%d, ", length);

            unsigned short name_index;
            fread(&name_index, sizeof(name_index), 1, fp);
            name_index = shortb2l(name_index);
            printf("变量名索引：#%d, ", name_index);

            printf("变量名：%s, ", find_utf8(name_index)->value);

            unsigned short descriptor_index;
            fread(&descriptor_index, sizeof(descriptor_index), 1, fp);
            descriptor_index = shortb2l(descriptor_index);
            printf("变量描述符索引：#%d, ", descriptor_index);
            printf("变量描述符：%s, ", find_utf8(descriptor_index)->value);

            unsigned short index;
            fread(&index, sizeof(index), 1, fp);
            index = shortb2l(index);
            printf("局部变量表索引：#%d\n", index);
        }
    }
    else if (!strcmp(value, "Code"))
    {
        //Code属性
        //Code_attribute {
        //     u2 attribute_name_index;
        //     u4 attribute_length;
        //     u2 max_stack;
        //     u2 max_locals;
        //     u4 code_length;
        //     u1 code[code_length];
        //     u2 exception_table_length;
        //     {
        //         u2 start_pc;
        //         u2 end_pc;
        //         u2 handler_pc;
        //         u2 catch_type;
        //     } exception_table[exception_table_length];
        //     u2 attributes_count;
        //     attribute_info attributes[attrbites_count];
        // }
        //max_stack项的值给出了当前方法的操作数栈在方法执行的任何时间点的最大深度
        unsigned short max_stack;
        fread(&max_stack, sizeof(max_stack), 1, fp);
        max_stack = shortb2l(max_stack);
        printf("stack=%d,", max_stack);

        //max_locals项的值给出了分配在当前方法引用的局部变量表中的局部变量给树，其中也包括调用此方法时用于传递参数的局部变量
        unsigned short max_locals;
        fread(&max_locals, sizeof(max_locals), 1, fp);
        max_locals = shortb2l(max_locals);
        printf("locals=%d,", max_locals);

        //code_length项的值给出了当前方法code[]数组的字节数 code_length的值必须大于0，即code[]数组不能为空
        unsigned int code_length;
        fread(&code_length, sizeof(code_length), 1, fp);
        code_length = intb2l(code_length);
        printf("code_length:%d\n", code_length);

        //code[code_length]
        unsigned char code;
        unsigned short u2;
        printf("Code:\n");
        int i = 0;
        while (i < code_length)
        {
            fread(&code, sizeof(code), 1, fp);
            /*
             0xb7 invokespecial 这条指令的作用是以栈顶的reference类型的数据所指向的对象作为方法接收者，调用此对象的
             实例构造器方法、private方法或者它的父类的方法。这个方法有一个u2类型的参数说明具体调用哪一个方法，它指向常量池中的一个CONSTANT_Methodref_info类型常量，即此方法的方法符合引用
            */
            if (code == 0xb7)
            {
                fread(&u2, sizeof(u2), 1, fp);
                u2 = shortb2l(u2);
                printf("%#x -> #%d \n", code, u2);
                i += 3;
            }
            else if (code == 0xb5)
            {
                fread(&u2, sizeof(u2), 1, fp);
                u2 = shortb2l(u2);
                printf("%#x -> #%d \n", code, u2);
                i += 3;
            }
            else if (code == 0xb4)
            {
                fread(&u2, sizeof(u2), 1, fp);
                u2 = shortb2l(u2);
                printf("%#x -> #%d \n", code, u2);
                i += 3;
            }
            else if (code == 0xb2)
            {
                fread(&u2, sizeof(u2), 1, fp);
                u2 = shortb2l(u2);
                printf("%#x -> #%d \n", code, u2);
                i += 3;
            }
            else if (code == 0xb6)
            {
                fread(&u2, sizeof(u2), 1, fp);
                u2 = shortb2l(u2);
                printf("%#x -> #%d \n", code, u2);
                i += 3;
            }
            else if (code == 0xa7)
            {
                fread(&u2, sizeof(u2), 1, fp);
                u2 = shortb2l(u2);
                printf("%#x -> %d \n", code, u2);
                i += 3;
            }
            else
            {
                printf("%#x\n", code);
                i++;
            }
        }

        //异常表成员个数
        unsigned short exception_table_length;
        fread(&exception_table_length, sizeof(exception_table_length), 1, fp);
        exception_table_length = shortb2l(exception_table_length);
        printf("异常表成员个数(exception_table_length):%d\n", exception_table_length);

        //解析异常表
        for (int i = 0; i < exception_table_length; i++)
        {
            // {
            //     u2 start_pc;
            //     u2 end_pc;
            //     u2 handler_pc;
            //     u2 catch_type;
            // } exception_table[exception_table_length];
            unsigned short start_pc;
            fread(&start_pc, sizeof(start_pc), 1, fp);
            start_pc = shortb2l(start_pc);
            printf("异常表start_pc:%d\n", exception_table_length);

            unsigned short end_pc;
            fread(&end_pc, sizeof(end_pc), 1, fp);
            end_pc = shortb2l(end_pc);
            printf("异常表end_pc:%d\n", end_pc);

            unsigned short handler_pc;
            fread(&handler_pc, sizeof(handler_pc), 1, fp);
            handler_pc = shortb2l(handler_pc);
            printf("异常表handler_pc:%d\n", handler_pc);

            unsigned short catch_type;
            fread(&catch_type, sizeof(catch_type), 1, fp);
            catch_type = shortb2l(catch_type);
            printf("异常表catch_type:#%d\n", catch_type);
        }

        //attributes_count Code属性子属性个数
        unsigned short attributes_count;
        fread(&attributes_count, sizeof(attributes_count), 1, fp);
        attributes_count = shortb2l(attributes_count);
        printf("Code属性子属性个数(attributes_count):%d\n", attributes_count);

        //解析Code属性子属性
        for (int i = 0; i < attributes_count; i++)
        {
            resolve_attr_table(fp);
        }
    }
    else if (!strcmp(value, "StackMapTable"))
    {
        //TODO
        char *content = (char *)malloc((attribute_length + 1) * sizeof(char));
        fread(content, attribute_length * sizeof(char), 1, fp);
        content[attribute_length] = '\0';
    }
    else if (!strcmp(value, "Exceptions"))
    {
        // Exceptions_attribute
        // {
        //     u2 attribute_name_index;
        //     u4 attribute_length;
        //     u2 number_of_exceptions;
        //     u2 exception_index_table[number_of_exceptions];
        // }
        unsigned short number_of_exceptions;
        fread(&number_of_exceptions, sizeof(number_of_exceptions), 1, fp);
        number_of_exceptions = shortb2l(number_of_exceptions);
        printf("受检异常个数:%d\n", number_of_exceptions);

        for (int i = 0; i < number_of_exceptions; i++)
        {
            unsigned short exception_index;
            fread(&exception_index, sizeof(exception_index), 1, fp);
            exception_index = shortb2l(exception_index);
            printf("受检异常索引:#%d\n", exception_index);
        }
    }
}